package com.bestvike.stone.spring.rabbit;

import com.bestvike.function.Func1;
import com.bestvike.linq.Linq;
import com.bestvike.stone.core.lang.StringUtils;
import com.rabbitmq.client.BuiltinExchangeType;
import com.rabbitmq.client.Channel;
import lombok.extern.apachecommons.CommonsLog;
import org.springframework.amqp.rabbit.connection.Connection;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.util.Assert;

/**
 * Created by 许崇雷 on 2019-01-09.
 */
@CommonsLog
public final class RabbitInfoUtils {
    private RabbitInfoUtils() {
    }

    public static void declareAll(ConnectionFactory connectionFactory) {
        Assert.notNull(connectionFactory, "connectionFactory can not be null");
        try (Connection connection = connectionFactory.createConnection();
             Channel channel = connection.createChannel(false)) {
            for (RabbitInfo rabbitInfo : RabbitInfo.REGISTERED)
                declare(rabbitInfo, channel);
        } catch (Exception ignored) {
        }
    }

    public static void declareAll(ConnectionFactory connectionFactory, String tag) {
        Assert.notNull(connectionFactory, "connectionFactory can not be null");
        try (Connection connection = connectionFactory.createConnection();
             Channel channel = connection.createChannel(false)) {
            for (RabbitInfo rabbitInfo : Linq.asEnumerable(RabbitInfo.REGISTERED).where(rabbitInfo -> StringUtils.equals(rabbitInfo.getTag(), tag)))
                declare(rabbitInfo, channel);
        } catch (Exception ignored) {
        }
    }

    public static void declareAll(ConnectionFactory connectionFactory, Func1<RabbitInfo, Boolean> predicate) {
        Assert.notNull(connectionFactory, "connectionFactory can not be null");
        Assert.notNull(predicate, "predicate can not be null");
        try (Connection connection = connectionFactory.createConnection();
             Channel channel = connection.createChannel(false)) {
            for (RabbitInfo rabbitInfo : Linq.asEnumerable(RabbitInfo.REGISTERED).where(predicate))
                declare(rabbitInfo, channel);
        } catch (Exception ignored) {
        }
    }

    public static void declare(RabbitInfo rabbitInfo, Channel channel) {
        Assert.notNull(rabbitInfo, "rabbitInfo can not be null");
        Assert.notNull(channel, "channel can not be null");
        if (StringUtils.isNotEmpty(rabbitInfo.getExchange()))
            try {
                channel.exchangeDeclare(rabbitInfo.getExchange(), BuiltinExchangeType.TOPIC, true, false, null);
            } catch (Exception e) {
                log.warn(String.format("declare exchange '%s' error.", rabbitInfo.getExchange()), e);
            }
        if (StringUtils.isNotEmpty(rabbitInfo.getQueue()))
            try {
                channel.queueDeclare(rabbitInfo.getQueue(), true, false, false, null);
            } catch (Exception e) {
                log.warn(String.format("declare queue '%s' error.", rabbitInfo.getQueue()), e);
            }
        if (StringUtils.isNotEmpty(rabbitInfo.getExchange()) && StringUtils.isNotEmpty(rabbitInfo.getQueue()) && StringUtils.isNotEmpty(rabbitInfo.getRoutingKey()))
            try {
                channel.queueBind(rabbitInfo.getQueue(), rabbitInfo.getExchange(), rabbitInfo.getRoutingKey(), null);
            } catch (Exception e) {
                log.warn(String.format("exchange '%s' bind to queue '%s' with routingKey '%s' error.", rabbitInfo.getExchange(), rabbitInfo.getQueue(), rabbitInfo.getRoutingKey()), e);
            }
    }

    public static void declare(RabbitInfo rabbitInfo, Connection connection) {
        Assert.notNull(connection, "connection can not be null");
        try (Channel channel = connection.createChannel(false)) {
            declare(rabbitInfo, channel);
        } catch (Exception ignored) {
        }
    }

    public static void declare(RabbitInfo rabbitInfo, ConnectionFactory connectionFactory) {
        Assert.notNull(connectionFactory, "connectionFactory can not be null");
        try (Connection connection = connectionFactory.createConnection()) {
            declare(rabbitInfo, connection);
        } catch (Exception ignored) {
        }
    }

    public static void declare(RabbitInfo rabbitInfo, RabbitTemplate rabbitTemplate) {
        Assert.notNull(rabbitTemplate, "rabbitTemplate can not be null");
        declare(rabbitInfo, rabbitTemplate.getConnectionFactory());
    }
}
